#ifndef VALUE_H
#define VALUE_H

/**
 * @copyright Copyright (c) 2025 
 * CSG Digital Grid Technology (Guangdong) Co., Ltd.
 * @author zhouyan
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

#ifdef CONFIG_64bit
#define EN_64bit
#endif

#ifdef CONFIG_ASSERT
#define ASSERT_EN
#endif

#ifdef ASSERT_EN
#include <cassert>
#define ASSERT(x) assert(x)
#else
#define ASSERT(x)
#endif

class Variate
{
public:
    enum Type {
        kIntFlag,
        kUintFlag,
        kFloatFlag,
        kStringFlag,
#ifdef EN_64bit
        kInt64Flag,
        kUint64Flag,
        kDoubleFlag,
#endif
    };

    explicit Variate(Type type);
    explicit Variate(int i);
    explicit Variate(uint32_t u);
    explicit Variate(float f);
#ifdef EN_64bit
    explicit Variate(int64_t i64);
    explicit Variate(uint64_t u64);
    explicit Variate(double d);
#endif

    //! Constructor for copy-string (i.e. do make a copy of string)
    explicit Variate(const char* s);

    ~Variate();

    Type GetType()  const { return flag_; }
    bool IsNumber() const { return (flag_ != kStringFlag); }
    bool IsInt()    const { return (flag_ == kIntFlag); }
    bool IsUint()   const { return (flag_ == kUintFlag); }
    bool IsFloat () const { return (flag_ == kFloatFlag); }
#ifdef EN_64bit
    bool IsInt64()  const { return (flag_ == kInt64Flag); }
    bool IsUint64() const { return (flag_ == kUint64Flag); }
    bool IsDouble() const { return (flag_ == kDoubleFlag); }
#endif
    bool IsString() const { return (flag_ == kStringFlag); }

    int32_t  GetInt() const     { ASSERT(flag_ == kIntFlag);    return data_.n.i; }
    uint32_t GetUint() const    { ASSERT(flag_ == kUintFlag);   return data_.n.u; }
    float    GetFloat() const;
#ifdef EN_64bit
    int64_t  GetInt64() const   { ASSERT(flag_ == kInt64Flag);  return data_.n.i64; }
    uint64_t GetUint64() const  { ASSERT(flag_ == kUint64Flag); return data_.n.u64; }
    double   GetDouble() const;
#endif
    const char* GetString() const { ASSERT(IsString()); return GetStringPointer(); }

    Variate& SetInt(int i);
    Variate& SetUint(unsigned u);
    Variate& SetFloat(float f);
#ifdef EN_64bit
    Variate& SetInt64(int64_t i64);
    Variate& SetUint64(uint64_t u64);
    Variate& SetDouble(double d);
#endif
    Variate& SetString(const char* s)  { this->~Variate(); SetStringRaw(s); return *this; }

protected:
    Variate(const Variate &);
    Variate& operator=(const Variate& rhs) {
        this->data_ = rhs.data_;
        this->flag_ = rhs.flag_;
        return *this;
    }

private:
    const char* GetStringPointer() const { return data_.s.str; }
    const char* SetStringPointer(const char* str) { return data_.s.str = str; }

    //! Initialize this value as copy string with initial data, without calling destructor.
    void SetStringRaw(const char * s);

private:
    union Number {
        int32_t i;
        uint32_t u;
        float f;
#ifdef EN_64bit
        int64_t i64;
        uint64_t u64;
        double d;
#endif
    };  // 4 bytes

    struct String {
//        uint32_t length;
        const char* str;
    };

    union Data {
        Number n;
        String s;
    };

    Data data_;
    Type flag_;
};

#endif // VALUE_H
